﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ExportRepositoryTests.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the ExportRepositoryTests type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace EFRepositoryTests
{
  using System;
  using System.Collections.Generic;
  using System.Configuration;
  using System.Linq;
  using System.Transactions;
  using Builder;
  using Entities;
  using FluentAssertions;
  using NUnit.Framework;
  using UnityRepository.Repositories;

  [Category("Integration")]
  [TestFixture]
  public class ExportRepositoryTests
  {
    private TransactionScope transactionScope;
    private ExportRepository exportRepository;
    private DocType docType;
    private SubDocType subDocType;
    private ManCo manCo;
    private Domicile domicile;

    [SetUp]
    public void Setup()
    {
      this.transactionScope = new TransactionScope();
      this.exportRepository = new ExportRepository(ConfigurationManager.ConnectionStrings["Unity"].ConnectionString) { BatchSize = 15 };
      this.domicile = BuildMeA.Domicile("code", "description");
      this.docType = BuildMeA.DocType("code", "description");
      this.subDocType = BuildMeA.SubDocType("code 1", "description 1").WithDocType(this.docType);
      this.manCo = BuildMeA.ManCo("description1", "code1").WithDomicile(this.domicile);
    }

    [TearDown]
    public void TearDown()
    {
      this.transactionScope.Dispose();
    }

    [Test]
    public void GivenAnExportCollectionOfZeroItems_WhenITryToSaveAndDeleteThem_NothingIsChanged()
    {
      Int32 initialCount = this.exportRepository.Entities.Count();

      var exports = new List<Export>();
      this.exportRepository.Create(exports);

      this.exportRepository.Entities.Count().Should().Be(initialCount);

      this.exportRepository.Delete(exports);

      this.exportRepository.Entities.Count().Should().Be(initialCount);
    }

    [Test]
    public void GivenAnExportCollection_WhenITryToSaveAndDeleteThemWithoutReloading_TheyAreAddedThenRemovedFromTheDB()
    {
      Int32 initialCount = this.exportRepository.Entities.Count();
      var exports = new List<Export>();

      const Int32 NumItems = 3;

      for (var i = 1; i <= NumItems; i++)
      {
        Document document =
          BuildMeA.Document(string.Format("document {0}", i))
            .WithDocType(this.docType)
            .WithSubDocType(this.subDocType)
            .WithManCo(this.manCo);

        Export export = BuildMeA.Export(DateTime.Now).WithDocument(document);

        exports.Add(export);
      }

      this.exportRepository.Create(exports);
      this.exportRepository.Entities.Count().Should().Be(initialCount + NumItems);

      this.exportRepository.Delete(exports);
      this.exportRepository.Entities.Count().Should().Be(initialCount);
    }

    [Test]
    public void GivenAnExportCollectionOfLessThanABatchNumberOfItems_WhenITryToSaveAndDeleteThem_TheyAreAddedThenRemovedFromTheDB()
    {
      Int32 initialCount = this.exportRepository.Entities.Count();

      var exports = new List<Export>();

      Int32 thirdOfABatchSize = Convert.ToInt32(this.exportRepository.BatchSize / 3);

      for (var i = 1; i <= thirdOfABatchSize; i++)
      {
        Document document = BuildMeA.Document(string.Format("document {0}", i))
                    .WithDocType(this.docType)
                    .WithSubDocType(this.subDocType)
                    .WithManCo(this.manCo);

        Export export = BuildMeA.Export(DateTime.Now).WithDocument(document);

        exports.Add(export);
      }

      this.exportRepository.Create(exports);
      this.exportRepository.Entities.Count().Should().Be(initialCount + thirdOfABatchSize);

      List<Int32> documentIds = exports.Select(e => e.DocumentId).ToList();
      List<Export> exportsReloaded =
        this.exportRepository.Entities.Where(export => documentIds.Contains(export.DocumentId)).ToList();

      exportsReloaded.Count.Should().Be(thirdOfABatchSize);

      this.exportRepository.Delete(exportsReloaded);
      this.exportRepository.Entities.Count().Should().Be(initialCount);
    }

    [Test]
    public void GivenAnExportCollectionOfExactlyABatchNumberOfItems_WhenITryToSaveAndDeleteThem_TheyAreAddedThenRemovedFromTheDB()
    {
      Int32 initialCount = this.exportRepository.Entities.Count();

      var exports = new List<Export>();

      Int32 batchSize = this.exportRepository.BatchSize;

      for (var i = 1; i <= batchSize; i++)
      {
        Document document = BuildMeA.Document(string.Format("document {0}", i))
                    .WithDocType(this.docType)
                    .WithSubDocType(this.subDocType)
                    .WithManCo(this.manCo);

        Export export = BuildMeA.Export(DateTime.Now).WithDocument(document);

        exports.Add(export);
      }

      this.exportRepository.Create(exports);
      this.exportRepository.Entities.Count().Should().Be(initialCount + batchSize);

      List<Int32> documentIds = exports.Select(e => e.DocumentId).ToList();
      List<Export> exportsReloaded =
        this.exportRepository.Entities.Where(export => documentIds.Contains(export.DocumentId)).ToList();

      this.exportRepository.Delete(exportsReloaded);
      this.exportRepository.Entities.Count().Should().Be(initialCount);
    }

    [Test]
    public void GivenAnExportCollectionOfMoreThanABatchNumberOfItems_WhenITryToSaveAndDeleteThem_TheyAreAddedThenRemovedFromTheDB()
    {
      Int32 initialCount = this.exportRepository.Entities.Count();

      var exports = new List<Export>();

      Int32 twoAndABitBatches = Convert.ToInt32(this.exportRepository.BatchSize * 2.2);

      for (var i = 1; i <= twoAndABitBatches; i++)
      {
        Document document = BuildMeA.Document(string.Format("document {0}", i))
                    .WithDocType(this.docType)
                    .WithSubDocType(this.subDocType)
                    .WithManCo(this.manCo);

        Export export = BuildMeA.Export(DateTime.Now).WithDocument(document);

        exports.Add(export);
      }

      this.exportRepository.Create(exports);
      this.exportRepository.Entities.Count().Should().Be(initialCount + twoAndABitBatches);

      List<Int32> documentIds = exports.Select(e => e.DocumentId).ToList();
      List<Export> exportsReloaded =
        this.exportRepository.Entities.Where(export => documentIds.Contains(export.DocumentId)).ToList();

      this.exportRepository.Delete(exportsReloaded);
      this.exportRepository.Entities.Count().Should().Be(initialCount);
    }
  }
}
